package com.sqlweb.sqlweb.base;

import lombok.extern.slf4j.Slf4j;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;

import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

@Slf4j
public class DynamicTest {
    private static final String RSERVE_HOST = "localhost";
    private static final int RSERVE_PORT = 6311;
    private static final Map<String, UserSession> userSessions = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        // 启动 Rserve 服务并添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                RConnection conn = new RConnection(RSERVE_HOST, RSERVE_PORT);
                conn.eval("quit('no')"); // 关闭 Rserve
                conn.close();
            } catch (Exception e) {
                log.error("Error shutting down Rserve", e);
            }
        }));
        log.info("Rserve 服务已启动，端口: " + RSERVE_PORT);

        // 初始化用户会话
        try {
            log.info("初始化用户1会话");
            UserSession user1 = new UserSession("user1", "E:/CAT/Item parameter file.csv");

            // 模拟用户答题
            log.info("模拟用户答题，用户1回答 3 道题");
            simulateUserTesting(user1, 3);
        } catch (RserveException e) {
            log.error("Rserve exception occurred", e);
        } catch (Exception e) {
            log.error("Unexpected exception occurred", e);
        } finally {
            // 确保关闭所有用户会话
            userSessions.values().forEach(UserSession::close);
        }
    }

    /**
     * 模拟用户答题
     *
     * @param userSession 用户会话
     * @param numQuestions 问题数量
     */
    private static void simulateUserTesting(UserSession userSession, int numQuestions) {
        for (int q = 0; q < numQuestions; q++) {
            try {
                // 获取下一题
                int nextQuestion = userSession.getNextQuestion();
                log.info("User: " + userSession.getUserId() + ", 下一个题目: " + nextQuestion);

                if (nextQuestion == -1) {
                    log.error("没有可选题目或出现错误，停止模拟答题。");
                    break;
                }

                // 模拟用户随机回答（1到5之间的值）
                int answer = (int) (Math.random() * 5) + 1;
                log.info("User: " + userSession.getUserId() + ", Answer: " + answer);

                // 提交答案
                userSession.submitAnswer(nextQuestion, answer);
            } catch (Exception e) {
                log.error("处理用户问题时出现错误: " + userSession.getUserId(), e);
            }
        }

        log.info("User: " + userSession.getUserId() + ", 最终能力值: " + userSession.getTheta());
    }

    /**
     * 用户会话类
     */
    static class UserSession implements AutoCloseable {
        private final String userId;
        private final String itemParameterPath;
        private final RConnection rConnection;
        private double theta = 0.0; // 初始能力值
        private int[] responses; // 用户的应答记录

        /**
         * 构造用户会话
         *
         * @param userId 用户ID
         * @param itemParameterPath 题目参数文件路径
         * @throws RserveException Rserve连接异常
         */
        public UserSession(String userId, String itemParameterPath) throws RserveException {
            this.userId = userId;
            this.itemParameterPath = itemParameterPath;
            this.rConnection = new RConnection(RSERVE_HOST, RSERVE_PORT);

            // 动态获取题目数量并初始化 responses 数组
            int numQuestions = getNumQuestions();
            this.responses = new int[numQuestions];
            Arrays.fill(this.responses, -1); // 初始化为未回答的状态（-1）

            // 初始化 R 环境
            initializeRSession();
        }

        /**
         * 获取题目数量
         *
         * @return 题目数量
         */
        private int getNumQuestions() {
            try {
                REXP result = rConnection.eval(String.format(
                        "nrow(read.csv('%s', header=FALSE))", itemParameterPath
                ));
                return result.asInteger();
            } catch (Exception e) {
                log.error("获取题目数量失败，设置默认值为 0", e);
                return 0;
            }
        }

        /**
         * 初始化 R 环境
         */
        private void initializeRSession() {
            try {
                // 加载 R 脚本
                log.info("加载 R 脚本: source('E:/CAT/fun.R')");
                rConnection.eval("source('E:/CAT/fun.R')");

                // 设置 R 中的文件路径
                rConnection.assign("filename.par", itemParameterPath);
            } catch (Exception e) {
                log.error("初始化 R 会话失败: " + userId, e);
            }
        }

        /**
         * 获取下一道题
         *
         * @return 下一道题的序号
         */
        public int getNextQuestion() {
            try {
                log.info("当前能力值 (Theta): " + theta);
                log.info("当前答题记录 (Responses): " + Arrays.toString(responses));

                // 将 Java 数组传递到 R 中
                rConnection.assign("respData", responses);

                // 调用 R 中的 selectQuestion 函数
                String rCommand = String.format(
                        "selectQuestion(currentTheta = %.2f, respData = respData, itemParPath = '%s')",
                        theta, itemParameterPath
                );
                log.info("执行 R 命令: " + rCommand);

                REXP result = rConnection.eval(rCommand);
                return result.asInteger();
            } catch (Exception e) {
                log.error("获取下一题时出错", e);
                return -1;
            }
        }

        /**
         * 提交用户答案并更新能力值
         *
         * @param questionId 问题ID
         * @param answer 用户答案
         */
        public void submitAnswer(int questionId, int answer) {
            try {
                // 更新指定题目索引的答案
                responses[questionId - 1] = answer; // 确保更新正确的题目索引

                // 将更新的答案传递到 R 中
                rConnection.assign("respData", responses);

                // 调用 R 中的能力值估计函数
                String rCommand = String.format(
                        "calcEAP(respData = respData, itemParPath = '%s')",
                        itemParameterPath
                );
                log.info("执行 R 命令: " + rCommand);

                REXP result = rConnection.eval(rCommand);
                theta = result.asList().at("theta").asDouble();  // 更新能力值

                log.info("更新后的能力值 (Theta): " + theta);
            } catch (Exception e) {
                log.error("提交答案时出错", e);
            }
        }


        public String getUserId() {
            return userId;
        }

        public double getTheta() {
            return theta;
        }

        @Override
        public void close() {
            try {
                if (rConnection != null) {
                    rConnection.close();
                }
            } catch (Exception e) {
                log.error("关闭 R 连接失败: " + userId, e);
            }
        }
    }
}
